import datetime

import jwt
from django.core.cache import caches
from django.db.transaction import atomic
from django.utils import timezone
from django.utils.decorators import method_decorator
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.decorators import api_view, authentication_classes, action, permission_classes
from rest_framework.filters import OrderingFilter
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet

from api.auths import CustomAuthentication, AllowPostAuthentication, CustomAuthorization
from api.filters import AgentFilterSet, HouseInfoFilterSet
from api.serializers import DistrictSimpleSerializer, DistrictDetailSerializer, HouseTypeSerializer, \
    AgentDetailSerializer, HouseInfoSimpleSerializer, EstateDetailSerializer, HouseInfoDetailSerializer, \
    EstatePostSerializer, TagSerializer, HouseInfoPostSerializer, UserPostSerializer, UserSimpleSerializer, \
    UserUpdateSerializer, HousePhotoSerializer, UserBasicSerializer
from api.utils import gen_mobile_code, send_sms_by_luosimao, to_md5_hex, get_ip_address, TEL_PATTERN
from common.models import District, HouseType, Agent, HouseInfo, Estate, Tag, User, UserToken, LoginLog, HousePhoto
from fangtx.settings import SECRET_KEY


@api_view(['POST'])
@authentication_classes((AllowPostAuthentication, ))
@permission_classes(())
def login(request):
    username = request.data.get('username')
    password = request.data.get('password')
    if username and password:
        password = to_md5_hex(password)
        user = User.objects.filter(username=username, password=password).first()
        if user:
            payload = {
                'exp': datetime.datetime.utcnow() + datetime.timedelta(days=1),
                'data': {'userid': user.userid}
            }
            token = jwt.encode(payload, SECRET_KEY, algorithm='HS256').decode()
            with atomic():
                current_time = timezone.now()
                if not user.lastvisit or \
                        (current_time - user.lastvisit).days >= 1:
                    user.point += 2
                    user.lastvisit = current_time
                    user.save()
                loginlog = LoginLog()
                loginlog.user = user
                loginlog.logdate = current_time
                loginlog.ipaddr = get_ip_address(request)
                loginlog.save()
            data = {'code': 20001, 'token': token}
        else:
            data = {'code': 20002, 'hint': '用户名或密码错误'}
    else:
        data = {'code': 20003, 'hint': '请输入有效的登录信息'}
    return Response(data)


@api_view(['GET'])
@permission_classes(())
def send_code_by_sms(request, tel):
    if TEL_PATTERN.fullmatch(tel):
        if caches['default'].get(tel):
            data = {'code': 10002, 'msg': '请不要在120秒以内重复发送手机验证码'}
        else:
            code = gen_mobile_code()
            message = f'您的短信验证码是{code}，打死也不能告诉别人哟！【Python小课】'
            # 消息的生产者 - 负责向消息队列产生一个任务（消息）
            # 消息的消费者 - celery -A fangtx worker -l debug
            send_sms_by_luosimao.delay(tel, message=message)
            caches['default'].set(tel, code, timeout=120)
            data = {'code': 10001, 'msg': '短信验证码发送成功'}
    else:
        data = {'code': 10003, 'msg': '请提供有效的手机号'}
    return Response(data)


class ProvinceView(ListAPIView):
    queryset = District.objects.filter(parent__isnull=True).only('distid', 'name')
    serializer_class = DistrictSimpleSerializer
    pagination_class = None


class DistrictView(RetrieveAPIView):
    queryset = District.objects.all()
    serializer_class = DistrictDetailSerializer


class HotCityView(ListAPIView):
    queryset = District.objects.filter(ishot=True).only('distid', 'name')
    serializer_class = DistrictSimpleSerializer
    pagination_class = None


class HouseTypeViewSet(ModelViewSet):
    queryset = HouseType.objects.all()
    serializer_class = HouseTypeSerializer
    pagination_class = None


class AgentViewSet(ModelViewSet):
    queryset = Agent.objects.all().prefetch_related('estates')
    serializer_class = AgentDetailSerializer
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    filterset_class = AgentFilterSet
    ordering = ('-servstar', )
    ordering_fields = ('servstar', 'realstar', 'agentid')


class EstateViewSet(ModelViewSet):
    queryset = Estate.objects.all().select_related('district').order_by('estateid')
    serializer_class = EstateDetailSerializer
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    filterset_fields = ('district', )
    ordering = ('-hot', )

    def get_serializer_class(self):
        if self.action in ('create', 'update'):
            return EstatePostSerializer
        return self.serializer_class


class TagViewSet(ModelViewSet):
    queryset = Tag.objects.all()
    serializer_class = TagSerializer


class HouseInfoViewSet(ModelViewSet):
    queryset = HouseInfo.objects.all()
    serializer_class = HouseInfoDetailSerializer
    filter_backends = (OrderingFilter, DjangoFilterBackend)
    filterset_class = HouseInfoFilterSet
    ordering = ('-pubdate', )

    @action(methods=('GET', ), detail=True)
    def photos(self, request, pk):
        house = self.get_object()
        queryset = HousePhoto.objects.filter(house=house)
        return Response(HousePhotoSerializer(queryset, many=True).data)

    def get_queryset(self):
        if self.action == 'list':
            return self.queryset\
                .only('houseid', 'title', 'area', 'floor', 'totalfloor', 'price',
                      'priceunit', 'street', 'district_level3', 'type')\
                .select_related('district_level3', 'type')\
                .prefetch_related('tags')
        return self.queryset\
            .defer('user', 'district_level2')\
            .select_related('district_level3', 'type', 'estate', 'agent')\
            .prefetch_related('tags')

    def get_serializer_class(self):
        if self.action == 'list':
            return HouseInfoSimpleSerializer
        elif self.action in ('create', 'update'):
            return HouseInfoPostSerializer
        return self.serializer_class


@method_decorator(decorator=atomic(), name='create')
class UserViewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserBasicSerializer
    authentication_classes = (AllowPostAuthentication, CustomAuthentication)

    def get_serializer_class(self):
        if self.action == 'create':
            return UserPostSerializer
        elif self.action == 'update':
            return UserUpdateSerializer
        return self.serializer_class
